iT邦幫忙

2025 iThome 鐵人賽

DAY 20
1

鐵匠史密斯在此~
昨日已經知道了視角的轉動速率與硬體規格,也就是影格刷新速率(frame rate = fps) 有關
我們今天直接上Code吧~

使用C++ 標準庫的 chrono 來得出影格刷新速率吧!

std::chrono 是一個 C++ 11 後建立的套件,以物件導向的方式來記錄時間戳以及時間的處理(sleep, 秒、毫秒轉換等等),詳情可以見Refernce處的 Cpp Reference: Date and time library 以及 Heresy's Space: C++11 STL 的時間函式庫:chrono

由於我們的主控台畫面緩衝區 screen 是將一格一格畫面呈現在螢幕上的
這就是目前第一層 while 迴圈的作用
所以,我們需要在每一個 while 迴圈,也就是影格刷新的時候,去紀錄到下一張影格需要花多少時間


    // Create world map
    std::wstring map{};

    map += L"################";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"################";


    // Get two time point to get frame rate
    auto tp1 { chrono::system_clock::now() };
    auto tp2 { chrono::system_clock::now() };


    while (true) {
        ...

初始化了兩個時間戳 tp1 以及 tp2 ,以便在刷新影格時(while 迴圈內) 紀錄時間差

    // Get two time point to get frame rate
    auto tp1 { chrono::system_clock::now() };
    auto tp2 { chrono::system_clock::now() };
    
    while (true) {
        // Get frame rate per loop
        tp2 = chrono::system_clock::now();
        chrono::duration<float> elaspedTime = tp2 - tp1;
        tp1 = tp2;
        float fElaspedTime{ elaspedTime.count() };
        ...

紀錄末時間點 tp2
而得出時間差 elaspedTime = 末時間點 - 初時間點 = tp2 - tp1
再把初時間點 tp1 賦值成當下的末時間點 tp2 ,以便為下一輪迴圈(影格)的初始時間點

這裡簡單說明:
chrono::duration<float> elaspedTime 是一個儲存資料的型別,如果要使這個型別儲存 float 的話,就是儲存float 為單位的秒數:

#include <iostream>
#include <chrono>



using namespace std;

int main(){
    auto tp1 { chrono::system_clock::now() };
    std::cout << "Hello World\n";
    auto tp2 { chrono::system_clock::now() };
    
    chrono::duration<float> elaspedTime = tp2 - tp1;
    
    std::cout << "Printing took "
      << elaspedTime.count()
      << " for second" << std::endl;
      
    return 0;
}

顯示的結果為:
https://ithelp.ithome.com.tw/upload/images/20250820/20157653y5Q3K89ccv.png

所以,可以回到 main() 函式內,我們知道了時間差,從昨日的Day 19 文章,我可以藉由時間差,也就是週期 T, 來調節影格刷新速率 f,那我們在**每格影格刷新時,按特定按鈕 (QA)後,所調整的角度如下: **

// Controls
// Handle rotation
if (GetAsyncKeyState((unsigned short)'Q') & 0x8000)
    fPlayerA += (0.1f) * fElaspedTime;

if (GetAsyncKeyState((unsigned short)'E') & 0x8000)
    fPlayerA -= (0.1f) * fElaspedTime;

如此一來,玩家的旋轉角度不再受不同的硬體限制,保持一定的速率進行旋轉!

今日總結

  • std::chrono : 處理時間的小幫手
  • 建立兩個時間戳,來記錄影格刷新時間
  • 藉由不同的影格刷新時間,調節轉動玩家方向 fPlayerA的速度

關於玩家旋轉的小撇步就先到這裡~
後面將會介紹牆面渲染的小工具,
說起來,我擔心30天的文案應該不足以把我想推導的,想補充的內容都奉上,但後面會一直持續維護這個系列的~
路還很長,我們繼續走下去~

Reference

  1. Cpp Reference: Date and time library
  2. Heresy's Space: C++11 STL 的時間函式庫:chrono

上一篇
Day19 | Ray Casting: 視角的轉動 - Part 2
下一篇
Day21 | Ray Casting: 渲染牆壁 - Part 1
系列文
用 C++ 實作簡易第一人稱視角遊戲:從入門到理解 Ray Casting30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言